﻿using Microsoft.Win32;
using SkiaSharp;
using SkiaSharp.Views.Desktop;
using SkiaSharp.Views.WPF;
using System;
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Threading;

namespace XY.WpfControlLibrary
{
    public partial class AOISK : UserControl, IDisposable
    {
        private SKBitmap img;
        private SKPoint imageOffset = new SKPoint(0, 0);
        private float zoom = 1.0f;
        private SKRect rectImg = new SKRect(0, 0, 100, 100);
        private SKColor sampleColor;
        private SKPoint imageCoord = new SKPoint(0, 0);
        private Point mouseStart;
        private bool dragging = false;
        private int clickCount = 0;
        private bool needUpdate = false;

        private readonly DispatcherTimer clickTimer;
        private readonly DispatcherTimer refreshTimer;

        public AOISK()
        {
            InitializeComponent();

            // 事件绑定
            skElement.PaintSurface += OnPaintSurface;
            skElement.MouseWheel += OnMouseWheel;
            skElement.MouseDown += OnMouseDown;
            skElement.MouseUp += (_, __) => dragging = false;
            skElement.MouseMove += OnMouseMove;
            skElement.Drop += OnDrop;
            skElement.SizeChanged += (_, __) => FitImage();
            skElement.AllowDrop = true;
            openFile.Click += OpenFile_Click;

            // 定时器初始化
            clickTimer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(300) };
            clickTimer.Tick += (_, __) => { clickTimer.Stop(); clickCount = 0; };

            refreshTimer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(33) };
            refreshTimer.Tick += (_, __) =>
            {
                if (needUpdate)
                {
                    skElement.InvalidateVisual();
                    needUpdate = false;
                }
            };
            refreshTimer.Start();
        }

        private void OpenFile_Click(object sender, RoutedEventArgs e)
        {
            var dialog = new OpenFileDialog
            {
                Filter = "Image Files|*.bmp;*.jpg;*.jpeg;*.png"
            };
            if (dialog.ShowDialog() == true)
            {
                LoadImage(dialog.FileName);
            }
        }

        private void OnDrop(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop) is false) return;

            var files = (string[])e.Data.GetData(DataFormats.FileDrop);
            if (files.Length > 0)
                LoadImage(files[0]);
        }

        private void LoadImage(string path)
        {
            img?.Dispose();
            img = SKBitmap.Decode(path);
            FitImage();
        }

        private void OnMouseDown(object sender, MouseButtonEventArgs e)
        {
            if (e.LeftButton != MouseButtonState.Pressed) return;

            dragging = true;
            mouseStart = e.GetPosition(skElement);
            clickCount++;

            if (clickCount == 1)
            {
                clickTimer.Start();
            }
            else if (clickCount == 2)
            {
                clickTimer.Stop();
                clickCount = 0;
                FitImage(); // double-click to fit
            }
        }

        private void OnMouseMove(object sender, MouseEventArgs e)
        {
            var pos = e.GetPosition(skElement);
            var offset = pos - mouseStart;

            if (dragging)
            {
                var dpiScale = GetDPIScale();
                imageOffset.X += (float)(offset.X * dpiScale.X);
                imageOffset.Y += (float)(offset.Y * dpiScale.Y);
                mouseStart = pos;
                needUpdate = true;
            }

            if (img != null)
            {
                imageCoord = GetImageCoord(pos);
                if (imageCoord.X >= 0 && imageCoord.Y >= 0 &&
                    imageCoord.X < img.Width && imageCoord.Y < img.Height)
                {
                    sampleColor = img.GetPixel((int)imageCoord.X, (int)imageCoord.Y);
                    needUpdate = true;
                }
            }
        }

        private void OnMouseWheel(object sender, MouseWheelEventArgs e)
        {
            var oldZoom = zoom;
            zoom *= (e.Delta > 0) ? 1.2f : 0.8f;
            zoom = Math.Max(zoom, 0.1f);

            var dpiScale = GetDPIScale();
            var mousePos = e.GetPosition(skElement);
            var scaledMousePos = new SKPoint(
                (float)(mousePos.X * dpiScale.X),
                (float)(mousePos.Y * dpiScale.Y));

            var zoomRatio = zoom / oldZoom;
            imageOffset.X = scaledMousePos.X - (scaledMousePos.X - imageOffset.X) * zoomRatio;
            imageOffset.Y = scaledMousePos.Y - (scaledMousePos.Y - imageOffset.Y) * zoomRatio;

            needUpdate = true;
        }

        private void FitImage()
        {
            if (img == null) return;

            zoom = 1.0f;
            var canvasSize = skElement.CanvasSize;
            float scaleX = canvasSize.Width / img.Width;
            float scaleY = canvasSize.Height / img.Height;
            float scale = Math.Min(scaleX, scaleY);

            float newWidth = img.Width * scale;
            float newHeight = img.Height * scale;

            imageOffset.X = (canvasSize.Width - newWidth) / 2f;
            imageOffset.Y = (canvasSize.Height - newHeight) / 2f;

            rectImg = new SKRect(0, 0, newWidth, newHeight);
            needUpdate = true;
        }

        private void OnPaintSurface(object sender, SKPaintSurfaceEventArgs e)
        {
            var sw = Stopwatch.StartNew();
            var canvas = e.Surface.Canvas;
            canvas.Clear(SKColors.White);

            if (img != null)
            {
                canvas.Save();
                canvas.Translate(imageOffset.X, imageOffset.Y);
                canvas.Scale(zoom, zoom);
                canvas.DrawBitmap(img, rectImg);
                DrawGrid(canvas);
                canvas.Restore();
            }

            // 绘制信息面板（动态宽高）
            var lines = new[]
            {
    $"坐标: ({imageCoord.X:0.##}, {imageCoord.Y:0.##}) 色值: R{sampleColor.Red} G{sampleColor.Green} B{sampleColor.Blue}",
    $"缩放: {zoom:0.##}x",
    $"耗时: {sw.ElapsedMilliseconds}ms"
};

            var textPaint = new SKPaint
            {
                Color = SKColors.White,
                TextSize = 22,
                IsAntialias = true,
                Typeface = SKTypeface.FromFamilyName("Microsoft YaHei", SKFontStyle.Normal)
            };

            // 计算最长文本宽度
            float padding = 12;
            float lineHeight = textPaint.TextSize + 6;
            float maxTextWidth = 0;

            foreach (var line in lines)
            {
                float width = textPaint.MeasureText(line);
                if (width > maxTextWidth)
                    maxTextWidth = width;
            }

            float panelWidth = maxTextWidth + padding * 2;
            float panelHeight = lines.Length * lineHeight + padding * 2;

            // 背景半透明框
            using var overlayPaint = new SKPaint
            {
                Color = new SKColor(0, 0, 0, 180),
                IsAntialias = true
            };
            canvas.DrawRect(new SKRect(0, 0, panelWidth, panelHeight), overlayPaint);

            // 绘制文字
            for (int i = 0; i < lines.Length; i++)
            {
                canvas.DrawText(lines[i], padding, padding + (i + 1) * lineHeight - 6, textPaint);
            }
        }

        private void DrawGrid(SKCanvas canvas)
        {
            if (zoom < 30 || img == null) return;

            float step = Math.Max(1, (int)(1 / zoom));
            float scaleX = img.Width / rectImg.Width;
            float scaleY = img.Height / rectImg.Height;

            using var gridPaint = new SKPaint
            {
                Color = SKColors.White,
                TextSize = 12 / zoom
            };

            for (int y = 0; y < img.Height; y += (int)step)
            {
                float sy = y / scaleY;
                canvas.DrawLine(0, sy, rectImg.Width, sy, gridPaint);
            }

            for (int x = 0; x < img.Width; x += (int)step)
            {
                float sx = x / scaleX;
                canvas.DrawLine(sx, 0, sx, rectImg.Height, gridPaint);
            }
        }

        private SKPoint GetImageCoord(Point controlPos)
        {
            if (img == null) return new SKPoint(0, 0);

            var dpiScale = GetDPIScale();
            float px = (float)(controlPos.X * dpiScale.X);
            float py = (float)(controlPos.Y * dpiScale.Y);

            float dx = (px - imageOffset.X) / zoom;
            float dy = (py - imageOffset.Y) / zoom;

            float imgX = dx * img.Width / rectImg.Width;
            float imgY = dy * img.Height / rectImg.Height;

            return new SKPoint(imgX, imgY);
        }

        private (double X, double Y) GetDPIScale()
        {
            var source = PresentationSource.FromVisual(this);
            var matrix = source?.CompositionTarget?.TransformToDevice ?? Matrix.Identity;
            return (matrix.M11, matrix.M22);
        }
        #region IDisposable Support
        private bool disposedValue = false;

        protected virtual void Dispose(bool disposing)
        {
            if (!disposedValue)
            {
                if (disposing)
                {
                    img?.Dispose();
                    clickTimer.Stop();
                    refreshTimer.Stop();
                }
                disposedValue = true;
            }
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
        #endregion
    }

   
}
